﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Mozlite.Components;
using Mozlite.WebUI.Ribbon;
using System.Web.Mvc.Html;
using System.Linq.Expressions;
using System.Web.Routing;

namespace Mozlite.WebUI.Mvc4.Backend
{
    /// <summary>
    /// HtmlHelper扩展方法类。
    /// </summary>
    public static class HtmlHelperExtensions
    {
        #region using scripts
        /// <summary>
        /// 引用脚本文件。
        /// </summary>
        /// <param name="helper">Html辅助方法类。</param>
        /// <param name="paths">引用路径。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString Script(this HtmlHelper helper, params string[] paths)
        {
            if (paths == null || paths.Length == 0)
                return MvcHtmlString.Empty;
            StringBuilder builder = new StringBuilder();
            foreach (var path in paths)
            {
                var url = "";
                if (path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || path.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                    url = path;
                else if (path.StartsWith("~"))
                    url = Cores.GetUrl(path);
                else
                    url = Cores.GetUrl("App_Areas", Consts.Backend, path);
                builder.AppendFormat("<script src=\"{0}\" type=\"text/javascript\"></script>", url);
            }
            return MvcHtmlString.Create(builder.ToString());
        }
        /// <summary>
        /// 引用样式文件。
        /// </summary>
        /// <param name="helper">Html辅助方法类。</param>
        /// <param name="paths">引用路径。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString Style(this HtmlHelper helper, params string[] paths)
        {
            if (paths == null || paths.Length == 0)
                return MvcHtmlString.Empty;
            StringBuilder builder = new StringBuilder();
            foreach (var path in paths)
            {
                var url = "";
                if (path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || path.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                    url = path;
                else if (path.StartsWith("~"))
                    url = Cores.GetUrl(path);
                else
                    url = Cores.GetUrl("App_Areas", Consts.Backend, path);
                builder.AppendFormat("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />", url);
            }
            return MvcHtmlString.Create(builder.ToString());
        }
        /// <summary>
        /// 引用脚本或样式文件。
        /// </summary>
        /// <param name="helper">Html辅助方法类。</param>
        /// <param name="paths">引用路径。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString Using(this HtmlHelper helper, params string[] paths)
        {
            if(paths == null || paths.Length == 0)
                return MvcHtmlString.Empty;
            StringBuilder builder = new StringBuilder();
            foreach(var path in paths)
            {
                var url = "";
                if(path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || path.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                    url = path;
                else if(path.StartsWith("~"))
                    url = Cores.GetUrl(path);
                else
                    url = Cores.GetUrl("App_Areas", Consts.Backend, path);
                if(url.EndsWith(".css", StringComparison.OrdinalIgnoreCase))
                    builder.AppendFormat("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />", url);
                else
                    builder.AppendFormat("<script src=\"{0}\" type=\"text/javascript\"></script>", url);
            }
            return MvcHtmlString.Create(builder.ToString());
        }
        /// <summary>
        /// 引用KendoUI脚本和样式。
        /// </summary>
        /// <param name="helper">Html辅助方法类。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString KendoUI(this HtmlHelper helper)
        {
            var skin = Cookies.GetCookie<KendoSkin>("kendoskin", GlobalSettings.Current.KendoSkin);
            return helper.KendoUI(skin);
        }
        /// <summary>
        /// 引用KendoUI脚本和样式。
        /// </summary>
        /// <param name="helper">Html辅助方法类。</param>
        /// <param name="skin">模板枚举。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString KendoUI(this HtmlHelper helper, KendoSkin skin)
        {
            return helper.Using(
                "~/app_utilities/kendo/kendo.web.min.js",
                "~/app_utilities/kendo/cultures/kendo.culture." + AppContext.Current.CultureName + ".min.js",
                "~/app_utilities/kendo/kendo.common.min.css",
                "~/app_utilities/kendo/kendo." + skin + ".min.css");
        }
        #endregion

        #region ribbons
        private static void AppendOrbItem(this HtmlHelper helper, Mozlite.WebUI.Ribbon.Item menu, StringBuilder builder)
        {
            builder.Append("<li><a");
            if(menu.Script.HasValue())
                builder.AppendFormat(" onclick=\"{0}\" href=\"javascript:void(0);\"", menu.Script);
            else if(menu.Href.HasValue())
            {
                builder.AppendFormat(" href=\"{0}\"", menu.Href);
                if(menu.Target.HasValue() && !menu.Target.IsCaseInsensitiveEqual("_self"))
                    builder.AppendFormat(" target=\"{0}\"", menu.Target);
            }
            builder.Append(">");
            builder.AppendFormat("<img src=\"{0}\" alt=\"{1}\" /><span>{1}</span></a>", menu.IconUrl,
                menu.IsLocalized ? helper.Local("Ribbon_"+menu.ItemName) : menu.ItemName);
        }

        private static void AppendItem(this HtmlHelper helper, Mozlite.WebUI.Ribbon.Item menu, StringBuilder builder)
        {
            builder.Append("<div");
            if(menu.Script.HasValue())
                builder.AppendFormat(" onclick=\"{0}\"", menu.Script);
            else if(menu.Href.HasValue())
            {
                builder.Append(" onclick=\"");
                if(menu.Target.HasValue() && "_top_parent".IndexOf(menu.Target.ToLower()) != -1)
                    builder.Append(menu.Target.Trim('_').ToLower() + ".");
                builder.AppendFormat("location.href = '{0}' + location.hash;\"", menu.Href);
            }
            builder.Append(">");
            if(menu.Display == "header" || menu.Display == "fixed")
            {
                builder.Append(menu.Html);
            }
            if(menu.Display != "fixed")
                builder.AppendFormat("<img src=\"{0}\" alt=\"{1}\" /><span>{1}</span></a>", menu.IconUrl,
                    menu.IsLocalized ? helper.Local("Ribbon_"+menu.ItemName) : menu.ItemName);
            if(menu.Display == "footer")
            {
                builder.Append(menu.Html);
            }
            builder.Append("</div>");
        }

        /// <summary>
        /// Ribbon控件。
        /// </summary>
        /// <param name="helper">Html辅助方法类。</param>
        /// <param name="path">配置文件物理路径。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString Ribbon(this HtmlHelper helper, string path = null)
        {
            var user = AppContext.Current.User;
            var ribbon = Ribbons.GetRibbon(path);
            var builder = new StringBuilder();
            builder.Append("<ul class=\"ribbon\"><li><ul class=\"orb\">");
            builder.AppendFormat("<li><a href=\"javascript:void(0);\"{0} class=\"orbButton\">&nbsp;</a><span>{1}</span>",
                ribbon.Orb.AccessKey == '\0' ? null : " accesskey=\"{0}\"".FormatWith(ribbon.Orb.AccessKey),
                ribbon.Orb.IsLocalized ? helper.Local("Ribbon_" + ribbon.Orb.OrbName) : ribbon.Orb.OrbName);
            builder.Append("<ul>");
            foreach (var menu in ribbon.Orb.Menu)
            {
                if (!user.IsAllowed(menu.RoleLevel))
                    continue;
                helper.AppendOrbItem(menu, builder);
                if (menu.Children != null && menu.Children.Count > 0)
                {
                    builder.Append("<ul>");
                    foreach (var item in menu.Children)
                    {
                        if(!user.IsAllowed(item.RoleLevel))
                            continue;
                        helper.AppendOrbItem(item, builder);
                        builder.Append("</li>");
                    }
                    builder.Append("</ul>");
                }
                builder.Append("</li>");
            }
            builder.Append("</ul></li></ul></li><li><ul class=\"menu\">");
            foreach (var menu in ribbon.Menu)
            {
                if(!user.IsAllowed(menu.RoleLevel))
                    continue;
                builder.AppendFormat("<li><a href=\"#{0}\"{1}>{2}</a>", menu.Key,
                menu.AccessKey == '\0' ? null : " accesskey=\"{0}\"".FormatWith(menu.AccessKey),
                menu.IsLocalized ? helper.Local("Ribbon_" + menu.Name) : menu.Name);
                if (menu.Groups.Count > 0)
                {
                    builder.Append("<ul>");
                    foreach (var group in menu.Groups)
                    {
                        if(!user.IsAllowed(group.RoleLevel))
                            continue;
                        builder.AppendFormat("<li><h2><span>{0}</span></h2>", group.IsLocalized ? helper.Local("Ribbon_" + group.GroupName) : group.GroupName);
                        foreach (var item in group.Menu)
                        {
                            if(!user.IsAllowed(item.RoleLevel))
                                continue;
                            if (item.IsSubItems)
                            {
                                builder.Append("<div class=\"ribbon-list\">");
                                for (var i = 0; i < item.Items.Count && i < 3; i++)
                                {
                                    if(!user.IsAllowed(item.Items[i].RoleLevel))
                                        continue;
                                    helper.AppendItem(item.Items[i], builder);
                                }
                                builder.Append("</div>");
                            }
                            else
                                helper.AppendItem(item, builder);
                        }
                    }
                    builder.Append("</ul>");
                }
                builder.Append("</li>");
            }
            builder.Append("</ul></li></ul><script type=\"text/javascript\">$('ul.ribbon').Ribbon();$('ul.menu').find('div[onclick]').each(function () {var click = $(this).attr('onclick');var regex = new RegExp('location.href = \\'(.*?)\\'', 'ig');if (regex.test(click) && RegExp.$1.toLowerCase() == location.pathname.toLowerCase()){$(this).addClass('current');}});</script>");
            return MvcHtmlString.Create(builder.ToString());
        }
        #endregion

        #region dropdownlist enum
        /// <summary>
        /// DropdownList控件。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString EnumDropdownListExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlExFor(Mvc4.HtmlHelperExtensions.EnumDropdownListFor, expression, htmlAttributes, warpperCssClass, "kendoui");
        }
        #endregion

        #region input extensions
        /// <summary>
        /// TextBox控件。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString TextBoxExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlExFor(InputExtensions.TextBoxFor, expression, htmlAttributes, warpperCssClass);
        }
        /// <summary>
        /// Password控件。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString PasswordExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlExFor(InputExtensions.PasswordFor, expression, htmlAttributes, warpperCssClass);
        }
        /// <summary>
        /// TextArea控件。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString TextAreaExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlExFor(TextAreaExtensions.TextAreaFor, expression, htmlAttributes, warpperCssClass);
        }

        private static MvcHtmlString TextAreaExt(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> htmlAttributes)
        {
            return htmlHelper.TextArea(name, value == null ? null : value.ToString(), htmlAttributes);
        }
        /// <summary>
        /// TextArea控件。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="value">值。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString TextAreaEx(this HtmlHelper htmlHelper, string name, object value = null, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlEx(TextAreaExt, name, value, htmlAttributes, warpperCssClass);
        }
        /// <summary>
        /// Password控件。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="value">值。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString PasswordEx(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlEx(InputExtensions.Password, name, value, htmlAttributes, warpperCssClass);
        }
        /// <summary>
        /// Password控件。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString PasswordEx(this HtmlHelper htmlHelper, string name, object htmlAttributes, string warpperCssClass = "lineinput")
        {
            return htmlHelper.PasswordEx(name, null, htmlAttributes, warpperCssClass);
        }
        /// <summary>
        /// Password控件。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString PasswordEx(this HtmlHelper htmlHelper, string name, string warpperCssClass = "lineinput")
        {
            return htmlHelper.PasswordEx(name, null, null, warpperCssClass);
        }
        #endregion

        #region button
        /// <summary>
        /// 提交按钮。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">名称，资源键。</param>
        /// <param name="iconCss">图标样式。</param>
        /// <param name="type">按钮类型。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString ButtonEx(this HtmlHelper htmlHelper, string name = "Submit", string iconCss = "k-update", string type = "submit", string warpperCssClass = "lineinput")
        {
            TagBuilder tag = new TagBuilder("div");
            tag.AddCssClass(warpperCssClass);
            string innerHtml = null;
            if(iconCss.HasValue())
                innerHtml = "<span class=\"k-icon {0}\"></span>".FormatWith(iconCss);
            innerHtml += " ";
            innerHtml += htmlHelper.Local(name);
            tag.InnerHtml = "<button type=\"{1}\" class=\"k-button\"> {0} </button>".FormatWith(innerHtml, type);
            return MvcHtmlString.Create(tag.ToString());
        }
        #endregion

        #region helpers
        /// <summary>
        /// 控件扩展，添加验证，后台属性输入项。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="func">呈现方法。</param>
        /// <param name="name">名称。</param>
        /// <param name="value">值。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <param name="defaultCssClass">控件默认样式表。</param>
        /// <returns>返回HTML字符串。</returns>
        private static MvcHtmlString ControlEx(this HtmlHelper htmlHelper, Func<HtmlHelper, string, object, IDictionary<string, object>, MvcHtmlString> func, string name, object value, object htmlAttributes, string warpperCssClass, string defaultCssClass = null)
        {
            var type = htmlHelper.ViewData.Model;
            var model = name;
            if (type != null)
                model = type.GetType().Name + "_" + name;
            TagBuilder tag = new TagBuilder("div");
            tag.AddCssClass(warpperCssClass);
            tag.InnerHtml = "<label>{0}</label>".FormatWith(htmlHelper.Local(model));
            bool isValidControl;
            tag.InnerHtml += htmlHelper.Control(name, value, htmlAttributes, func, defaultCssClass, out isValidControl).ToHtmlString();
            if (isValidControl)
                tag.InnerHtml += htmlHelper.ValidationMessage(name).ToHtmlString();
            tag.InnerHtml += "<p>{0}</p>".FormatWith(htmlHelper.Local("{0}_Summary".FormatWith(model)));
            return MvcHtmlString.Create(tag.ToString());
        }
        /// <summary>
        /// 控件扩展，添加验证，后台属性输入项。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="func">呈现方法。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <param name="defaultCssClass">控件默认样式表。</param>
        /// <returns>返回HTML字符串。</returns>
        private static MvcHtmlString ControlExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IDictionary<string, object>, MvcHtmlString> func, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, string warpperCssClass, string defaultCssClass = null)
        {
            var name = ExpressionHelper.GetExpressionText(expression);
            TagBuilder tag = new TagBuilder("div");
            tag.AddCssClass(warpperCssClass);
            tag.InnerHtml = "<label>{0}</label>".FormatWith(htmlHelper.Local("{0}_{1}".FormatWith(typeof(TModel).Name, name)));
            bool isValidControl;
            tag.InnerHtml += htmlHelper.ControlFor(expression, htmlAttributes, func, defaultCssClass, out isValidControl).ToHtmlString();
            if (isValidControl)
                tag.InnerHtml += htmlHelper.ValidationMessageFor(expression).ToHtmlString();
            tag.InnerHtml += "<p>{0}</p>".FormatWith(htmlHelper.Local("{0}_{1}_Summary".FormatWith(typeof(TModel).Name, name)));
            return MvcHtmlString.Create(tag.ToString());
        }
        #endregion

        #region languages
        /// <summary>
        /// 区域资源语言控件。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString CultureDropdownListExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlExFor(Mvc4.HtmlHelperExtensions.CultureDropdownListFor, expression, htmlAttributes, warpperCssClass, "kendoui moz-auto-change");
        }
        /// <summary>
        /// 区域资源语言控件。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="value">值。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="warpperCssClass">最外层DIV样式。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString CultureDropdownListEx(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes = null, string warpperCssClass = "lineinput")
        {
            return htmlHelper.ControlEx(Mvc4.HtmlHelperExtensions.CultureDropdownList, name, value, htmlAttributes, warpperCssClass, "kendoui moz-auto-change");
        }
        #endregion
    }
}
